﻿namespace OutLook.Model.Domains
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.Serialization;
    using OutLook.Model.Infrastructure;

    /// <summary>
    /// Description of charge material
    /// </summary>
    [DataContract]
    public class Charge : IAssignable, IEquatable<Charge>, IValidatable
    {
        #region Constructors

        /// <summary>
        /// Initializes new default instance of charge material
        /// </summary>
        private Charge() : this(string.Empty, new ChemicalСombination[0]) { }

        /// <summary>
        /// Initializes new instance of charge material
        /// </summary>
        /// <param name="title">Title of charge material</param>
        /// <param name="composition">Charge material composition</param>
        private Charge(string title, IEnumerable<ChemicalСombination> compositions)
        {
            Title = title;
            Compositions = new List<ChemicalСombination>(compositions);
            Wet = default(double);
            Volatiles = default(double);
            Z = default(double);
        }

        /// <summary>
        /// Initializes new instance of charge material
        /// </summary>
        /// <param name="title">Title of charge material</param>
        /// <param name="compositions">Charge material composition</param>
        /// <param name="moisture">TODO: Nastya</param>
        /// <param name="gab">TODO: Nastya</param>
        private Charge(string title, IEnumerable<ChemicalСombination> compositions, double wet, double volatiles, double z)
        {
            Title = title;
            Compositions = new List<ChemicalСombination>(compositions);
            Wet = wet;
            Volatiles = volatiles;
            Z = z;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Title of charge material
        /// </summary>
        [DataMember(Order = 1)]
        public string Title
        {
            get { return m_Title; }
            private set { m_Title = value; }
        }

        /// <summary>
        /// Wet of charge material
        /// </summary>
        [DataMember(Order = 3)]
        public double Wet
        {
            get { return m_Wet; }
            set { m_Wet = value; }
        }

        /// <summary>
        /// Volatiles of charge material
        /// </summary>
        [DataMember(Order = 4)]
        public double Volatiles
        {
            get { return m_Volatiles; }
            set { m_Volatiles = value; }
        }

        /// <summary>
        /// Ash in charge material (in percents)
        /// </summary>
        [DataMember(Order = 5)]
        public double Z
        {
            get { return m_Z; }
            set { m_Z = value; }
        }

        /// <summary>
        /// Charge material chemical composition
        /// </summary>
        [DataMember(Order = 2)]
        public List<ChemicalСombination> Compositions
        {
            get { return m_Compositions; }
            private set { m_Compositions = value; }
        }

        #endregion

        #region Factory Method

        /// <summary>
        ///  Creates new default instance of charge material 
        /// </summary>
        /// <returns>New default instance of charge material</returns>
        public static Charge Create()
        {
            return new Charge();
        }

        /// <summary>
        /// Creates new instance of charge material
        /// </summary>
        /// <param name="title">Title of charge material</param>
        /// <param name="compositions">Charge material composition</param>
        /// <returns>New instance of charge material</returns>
        public static Charge Create(string title, IEnumerable<ChemicalСombination> compositions)
        {
            return Charge.Create(title, compositions, default(double), default(double), default(double));
        }

        /// <summary>
        /// Creates new instance of charge material
        /// </summary>
        /// <param name="title">Title of charge material</param>
        /// <param name="compositions">Charge material composition</param>
        /// <param name="wet">TODO: Nastya</param>
        /// <param name="volatiles">TODO: Nastya</param>
        /// <returns>New instance of charge material</returns>
        /// <remarks>Can return NULL if input arguments were wrong<</remarks>
        public static Charge Create(string title, IEnumerable<ChemicalСombination> compositions, double wet, double volatiles, double z)
        {
            if (title == null || compositions == null)
                return null;

            return new Charge(title, compositions, wet, volatiles, z);
        }

        #endregion

        #region IAssignable Implementation

        /// <summary>
        /// Assigns values of current charge to the argument object
        /// </summary>
        /// <param name="obj">Object to assign to</param>
        /// <exception cref="ArgumentNullException">If object to assign to is nullable</exception>
        /// <exception cref="NotSupportedException">If object to assign to doesn't fit</exception>
        public void AssignTo(object obj)
        {
            if (obj == null)
                throw new ArgumentNullException();

            if (obj is Charge)
            {
                Charge charge = obj as Charge;
                charge.Title = m_Title;
                charge.Volatiles = m_Volatiles;
                charge.Wet = m_Wet;
                charge.Z = m_Z;
                charge.Compositions.Clear();

                foreach (ChemicalСombination item in m_Compositions)
                {
                    charge.Compositions.Add(item);
                }

                return;
            }

            throw new NotSupportedException();
        }

        #endregion

        #region IEquatable<Charge> Implementation

        /// <summary>
        /// Compares current Charge with another one
        /// </summary>
        /// <param name="other">Another Charge</param>
        /// <returns>True - If current Charge and another one are equal, otherwise - False</returns>
        public bool Equals(Charge other)
        {
            if (other == null)
                return false;

            if (!Title.Equals(other.Title) || Wet != other.Wet || Volatiles != other.Volatiles || Z != other.Z)
                return false;

            if (Compositions.Count != other.Compositions.Count)
                return false;

            bool result = true;
            for (int i = 0; i < Compositions.Count; i++)
            {
                if (!Compositions[i].Equals(other.Compositions[i]))
                {
                    result = false;
                    break;
                }
            }

            return result;
        }

        #endregion

        #region IValidatable Implementation

        /// <summary>
        /// Validates Charge
        /// </summary>
        /// <returns>True - if current Charge is valid, otherwise - false</returns>
        public bool Validate()
        {
            ///TODO:CHARGE VALIDATION 
            if (string.IsNullOrWhiteSpace(m_Title) || string.IsNullOrEmpty(m_Title))
                return false;

            if (m_Compositions.Count == 0)
                return false;

            return true;
        }

        #endregion

        #region Fields

        private string m_Title = default(string);
        private double m_Wet = default(double);
        private double m_Volatiles = default(double);
        private double m_Z = default(double);
        private List<ChemicalСombination> m_Compositions = default(List<ChemicalСombination>);

        #endregion
    }
}
